﻿
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace HCenter.CacheHelper
{
    public class CacheLock : IDisposable
    {
        private readonly ICacheProvider _cache = null;
        private readonly string key;
        private readonly string token;
        private bool con = false;
        public CacheLock(ICacheProvider cache, string _key, TimeSpan? timeOut = null, bool useLock = true, int lockCounter = 5)
        {
            _cache = cache;
            key = _key;
            token = Environment.MachineName;
            if (useLock == false)
                return;

            timeOut = timeOut ?? TimeSpan.FromSeconds(10);

            //var _timeOut = (timeOut == null ? TimeSpan.FromSeconds(20) : timeOut.Value).Add(TimeSpan.FromMilliseconds(100));
            //ExecUtils.RetryUntilTrue(() =>
            //{
            //    var __timeOut = (timeOut == null ? TimeSpan.FromSeconds(20) : timeOut.Value);

            //    con = _cache.LockTake(key, token, __timeOut);
            //    return con;

            //}, _timeOut);

            ////int lockCounter = 20;//for logging in case when too many locks per key
            //Random rd = new Random();
            //int rdCounter = 0;
            //while (lockCounter > 0)
            //{
            //    //check for access to cache object, trying to lock it
            //    con = cache.LockTake(key, token, timeOut);
            //    if (!con)
            //    {
            //        lockCounter--;
            //        var rdn = rd.Next(100, 300);
            //        Thread.Sleep(rdn); //sleep for 100 milliseconds for next lock try. you can play with that
            //        rdCounter += rdn;
            //        continue;
            //    }
            //    else 
            //    { break; }
            //}
            //if (lockCounter <= 0)
            //    throw new TimeoutException($"CacheLock Exceeded timeout of {timeOut.Value} + {rdCounter}ms");

            var _timeOut = TimeSpan.FromMilliseconds(timeOut.Value.TotalMilliseconds / 3);
            ExecUtils.PollyWaitAndRetry<TimeoutException, bool>(() =>
            {
                con = cache.LockTake(key, token, timeOut);
                if (!con)
                {
                    throw new TimeoutException($"CacheLock Exceeded timeout of {timeOut.Value}");
                }
                return con;
            }, lockCounter, _timeOut);
        }

        public void Dispose()
        {
            if (con)
            {
                _cache.LockRelease(key, token);
            }
        }
    }
}
